package com.aps.demo;

import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * APS排程调度器
 *
 * 基于遗传算法的高级排程系统核心调度器。
 * 负责将多个订单的工序在多台设备上进行优化排产，
 * 在满足工艺约束和时间约束的前提下，最大化设备利用率并最小化延迟。
 *
 * 遗传算法特点：
 * - 全局搜索能力强，能够跳出局部最优
 * - 适用于多目标优化问题
 * - 对问题的数学性质要求较低
 * - 可以处理复杂的约束条件
 *
 * @author APS System
 * @version 1.0
 */
@Slf4j
public class Scheduler {

    // ============ 遗传算法参数 ============

    /** 种群大小（每一代包含的染色体数量） */
    private int populationSize = 100;

    /** 最小种群大小 */
    private final int minPopulationSize = 10;

    /** 最大种群大小 */
    private final int maxPopulationSize = 100;

    /** 基础交叉概率（两个父代进行基因交换的概率） */
    private final double baseCrossoverRate = 0.8;

    /** 当前交叉概率（自适应调整） */
    private double crossoverRate = 0.8;

    /** 基础变异概率（基因发生随机变化的概率） */
    private final double baseMutationRate = 0.05;

    /** 当前变异概率（自适应调整） */
    private double mutationRate = 0.05;

    /** 最大进化代数（算法迭代次数） */
    private int maxGenerations = 50;

    /** 锦标赛选择的参与者数量 */
    private int tournamentSize = 3;

    /** 收敛阈值（用于检测算法是否已收敛） */
    private final double convergenceThreshold = 0.05;

    /** 连续无改进的最大代数（早停机制） */
    private final int maxStagnantGenerations = 10;

    /** 多样性权重（锦标赛选择中的多样性考虑） */
    private final double diversityWeight = 0.1;

    /** 精英保留比例 */
    private final double eliteRatio = 0.2;

    // ============ 排产参数 ============

    /** 排产模式 */
    private SchedulingMode schedulingMode;

    /** 待排产的订单列表 */
    private List<Order> orders;

    /** 可用设备列表 */
    private List<Machine> machines;

    /** 全局统一开始时间 */
    private LocalDateTime globalStartTime;

    // ============ 时间常量 ============

    /** 时间格式化器 */
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

    /** 加班开始时间（18:00） */
    private static final int OVERTIME_START_HOUR = 18;

    /** 加班结束时间（20:00） */
    private static final int OVERTIME_END_HOUR = 20;

    /** 工作开始时间（8:00） */
    private static final int WORK_START_HOUR = 8;

    /** 上午工作结束时间（12:00） */
    private static final int MORNING_END_HOUR = 12;

    /** 下午工作开始时间（13:00） */
    private static final int AFTERNOON_START_HOUR = 13;

    /** 正常工作结束时间（18:00） */
    private static final int WORK_END_HOUR = 18;

    /**
     * 构造函数
     *
     * @param mode 排产模式
     * @param orders 订单列表
     * @param machines 设备列表
     * @param globalStartTime 全局开始时间
     */
    public Scheduler(SchedulingMode mode, List<Order> orders, List<Machine> machines, LocalDateTime globalStartTime) {
        this.schedulingMode = mode;
        this.orders = orders != null ? orders : new ArrayList<>();
        this.machines = machines != null ? machines : new ArrayList<>();
        this.globalStartTime = globalStartTime;

        // 确保所有订单都使用统一的开始时间
        enforceGlobalStartTime();

        // 根据问题复杂度动态调整参数
        optimizeParameters();
    }

    /**
     * 根据问题复杂度优化算法参数
     */
    private void optimizeParameters() {
        // 计算总工序数量
        int totalOperations = orders.stream()
                .mapToInt(order -> order.getOperations().size())
                .sum();

        // 动态调整种群大小
        this.populationSize = GAUtils.calculateDynamicPopulationSize(
                totalOperations, minPopulationSize, maxPopulationSize);

        // 根据问题规模调整最大代数
        if (totalOperations > 20) {
            this.maxGenerations = Math.min(100, totalOperations * 3);
        }

        // 调整锦标赛大小
        this.tournamentSize = Math.max(2, Math.min(5, populationSize / 10));

        log.info("参数优化完成 - 工序数量: {}, 种群大小: {}, 最大代数: {}, 锦标赛大小: {}",
                totalOperations, populationSize, maxGenerations, tournamentSize);
    }

    /**
     * 确保所有订单都使用全局统一的开始时间
     *
     * 这是为了保证排产的一致性，避免不同订单有不同的开始时间
     * 导致的排产复杂度增加。
     */
    private void enforceGlobalStartTime() {
        for (Order order : orders) {
            order.setStartDate(globalStartTime);
        }
    }

    /**
     * 运行优化的遗传算法进行排产
     *
     * 增强版遗传算法流程：
     * 1. 混合策略初始化种群
     * 2. 自适应迭代进化：
     *    a) 计算适应度和多样性
     *    b) 自适应参数调整
     *    c) 多样性保护的选择
     *    d) 改进的交叉操作
     *    e) 自适应变异
     *    f) 精英保留选择
     *    g) 多重终止条件检查
     * 3. 返回最优解
     *
     * @return 最优排产方案（染色体）
     */
    public Chromosome schedule() {
        log.info("开始执行优化遗传算法排产...");
        log.info("初始参数 - 种群大小: {}, 最大代数: {}, 基础交叉率: {}, 基础变异率: {}",
                populationSize, maxGenerations, baseCrossoverRate, baseMutationRate);

        // 1. 混合策略初始化种群
        List<Chromosome> population = initializePopulationWithHeuristics();
        log.info("初始种群创建完成，共{}个染色体", population.size());

        // 进化统计记录
        double bestFitnessEver = 0.0;
        Chromosome bestChromosomeEver = null;
        int stagnantGenerations = 0;
        double[] fitnessHistory = new double[maxGenerations];

        // 2. 自适应进化迭代
        for (int generation = 0; generation < maxGenerations; generation++) {
            log.info("========== 第{}代进化开始 ==========", generation + 1);

            // 计算适应度
            calculateFitness(population);

            // 计算种群统计信息
            double[] stats = GAUtils.calculateFitnessStatistics(population);
            double diversity = GAUtils.calculateDiversity(population);
            fitnessHistory[generation] = stats[1]; // 记录最大适应度

            // 找到当前代最优个体
            Chromosome currentBest = population.stream()
                    .max(Comparator.comparingDouble(Chromosome::getFitness))
                    .orElse(null);

            // 更新全局最优
            if (currentBest != null && currentBest.getFitness() > bestFitnessEver) {
                bestFitnessEver = currentBest.getFitness();
                bestChromosomeEver = currentBest.copy();
                stagnantGenerations = 0;
                log.info("第{}代发现更优解，适应度: {:.6f}", generation + 1, bestFitnessEver);
            } else {
                stagnantGenerations++;
            }

            // 自适应参数调整
            double fitnessImprovement = calculateFitnessImprovement(fitnessHistory, generation);
            updateAdaptiveParameters(diversity, fitnessImprovement, generation);

            // 详细统计日志
            log.info("第{}代统计 - 最小: {:.4f}, 最大: {:.4f}, 平均: {:.4f}, 标准差: {:.4f}, 多样性: {:.4f}",
                    generation + 1, stats[0], stats[1], stats[2], stats[3], diversity);
            log.info("自适应参数 - 交叉率: {:.3f}, 变异率: {:.3f}, 停滞代数: {}",
                    crossoverRate, mutationRate, stagnantGenerations);

            // 多重终止条件检查
            if (shouldTerminate(population, generation, stagnantGenerations, diversity)) {
                log.info("满足终止条件，提前结束进化。原因：");
                if (stagnantGenerations >= maxStagnantGenerations) {
                    log.info("- 连续{}代无改进", stagnantGenerations);
                }
                if (GAUtils.isPopulationConverged(population, convergenceThreshold)) {
                    log.info("- 种群已收敛（阈值: {}）", convergenceThreshold);
                }
                break;
            }

            // 选择父代（多样性保护）
            List<Chromosome> parents = selectParentsWithDiversity(population);

            // 交叉产生子代
            List<Chromosome> offspring = crossover(parents);

            // 自适应变异
            mutate(offspring);

            // 精英保留替换种群
            population = replacePopulationWithElitism(population, offspring);

            log.info("第{}代进化完成", generation + 1);
        }

        // 3. 最终优化和结果输出
        calculateFitness(population);
        Chromosome finalBest = population.stream()
                .max(Comparator.comparingDouble(Chromosome::getFitness))
                .orElse(bestChromosomeEver);

        if (finalBest != null && finalBest.getFitness() > bestFitnessEver) {
            bestChromosomeEver = finalBest;
            bestFitnessEver = finalBest.getFitness();
        }

        log.info("遗传算法执行完成！");
        log.info("最优适应度: {:.6f}", bestFitnessEver);
        log.info("算法性能统计：");
        log.info("- 有效进化代数: {}", Math.min(maxGenerations, fitnessHistory.length));
        log.info("- 最终种群多样性: {:.4f}", GAUtils.calculateDiversity(population));

        return bestChromosomeEver;
    }

    /**
     * 计算适应度改进幅度
     *
     * @param fitnessHistory 适应度历史记录
     * @param currentGeneration 当前代数
     * @return 适应度改进幅度
     */
    private double calculateFitnessImprovement(double[] fitnessHistory, int currentGeneration) {
        if (currentGeneration < 5) {
            return 0.1; // 初始几代默认有改进
        }

        // 计算最近5代的平均改进
        double recentAvg = 0;
        double earlierAvg = 0;

        for (int i = Math.max(0, currentGeneration - 4); i <= currentGeneration; i++) {
            recentAvg += fitnessHistory[i];
        }
        recentAvg /= 5;

        for (int i = Math.max(0, currentGeneration - 9); i < currentGeneration - 4; i++) {
            earlierAvg += fitnessHistory[i];
        }
        earlierAvg /= 5;

        return Math.abs(recentAvg - earlierAvg);
    }

    /**
     * 更新自适应参数
     *
     * @param diversity 种群多样性
     * @param fitnessImprovement 适应度改进幅度
     * @param generation 当前代数
     */
    private void updateAdaptiveParameters(double diversity, double fitnessImprovement, int generation) {
        // 更新交叉率
        this.crossoverRate = GAUtils.calculateAdaptiveCrossoverRate(
                diversity, generation, maxGenerations, baseCrossoverRate);

        // 更新变异率
        this.mutationRate = GAUtils.calculateAdaptiveMutationRate(
                diversity, fitnessImprovement, baseMutationRate);
    }

    /**
     * 检查是否应该终止算法
     *
     * @param population 当前种群
     * @param generation 当前代数
     * @param stagnantGenerations 停滞代数
     * @param diversity 种群多样性
     * @return 是否应该终止
     */
    private boolean shouldTerminate(List<Chromosome> population, int generation,
                                   int stagnantGenerations, double diversity) {
        // 达到最大代数
        if (generation >= maxGenerations - 1) {
            return true;
        }

        // 连续无改进
        if (stagnantGenerations >= maxStagnantGenerations) {
            return true;
        }

        // 种群收敛
        if (GAUtils.isPopulationConverged(population, convergenceThreshold)) {
            return true;
        }

        // 多样性过低且长时间无改进
        if (diversity < 0.1 && stagnantGenerations >= maxStagnantGenerations / 2) {
            return true;
        }

        return false;
    }

    /**
     * 使用启发式规则的混合初始化策略
     *
     * 结合以下策略：
     * 1. 40%随机初始化（保证多样性）
     * 2. 20%最早交付日期优先（EDD规则）
     * 3. 20%最短处理时间优先（SPT规则）
     * 4. 20%最长处理时间优先（LPT规则）
     *
     * @return 初始种群
     */
    private List<Chromosome> initializePopulationWithHeuristics() {
        log.info("开始混合策略初始化种群========================================");
        log.info("策略分配：40%随机 + 20%EDD启发式 + 20%SPT启发式 + 20%LPT启发式");

        List<Chromosome> population = new ArrayList<>();
        List<Operation> allOperations = new ArrayList<>();

        // 收集所有工序
        for (Order order : orders) {
            allOperations.addAll(order.getOperations());
        }

        int randomCount = (int) (populationSize * 0.4);
        int eddCount = (int) (populationSize * 0.2);
        int sptCount = (int) (populationSize * 0.2);
        int lptCount = populationSize - randomCount - eddCount - sptCount;

        log.info("染色体分布：随机{}个，EDD{}个，SPT{}个，LPT{}个", randomCount, eddCount, sptCount, lptCount);

        // 40% 随机初始化
        for (int i = 0; i < randomCount; i++) {
            List<Operation> shuffled = new ArrayList<>(allOperations);
            shufflePreservingOrder(shuffled);
            population.add(new Chromosome(shuffled));
        }

        // 20% EDD (Earliest Due Date) 启发式
        for (int i = 0; i < eddCount; i++) {
            List<Operation> eddSequence = createEDDSequence(allOperations, i);
            population.add(new Chromosome(eddSequence));
            log.debug("生成EDD染色体{}，工序序列: {}", i,
                    eddSequence.stream().map(Operation::getId).collect(Collectors.joining(",")));
        }

        // 20% SPT (Shortest Processing Time) 启发式
        for (int i = 0; i < sptCount; i++) {
            List<Operation> sptSequence = createSPTSequence(allOperations, i);
            population.add(new Chromosome(sptSequence));
            log.debug("生成SPT染色体{}，工序序列: {}", i,
                    sptSequence.stream().map(Operation::getId).collect(Collectors.joining(",")));
        }

        // 20% LPT (Longest Processing Time) 启发式
        for (int i = 0; i < lptCount; i++) {
            List<Operation> lptSequence = createLPTSequence(allOperations, i);
            population.add(new Chromosome(lptSequence));
            log.debug("生成LPT染色体{}，工序序列: {}", i,
                    lptSequence.stream().map(Operation::getId).collect(Collectors.joining(",")));
        }

        log.info("混合策略初始化完成，生成{}个染色体", population.size());
        return population;
    }

    /**
     * 创建基于最早交付日期(EDD)的工序序列
     *
     * 硬约束保证：
     * 1. 工序执行顺序：同一订单的工序必须按sequence顺序执行
     * 2. 交付日期优先级：交付日期越早的订单优先级越高
     *
     * 启发式规则：在满足硬约束的前提下，严格按照交付日期排序
     *
     * @param allOperations 所有工序
     * @param variationIndex 变异索引，用于产生不同的随机扰动
     * @return EDD排序的工序序列
     */
    private List<Operation> createEDDSequence(List<Operation> allOperations, int variationIndex) {
        // 步骤1：严格按交付日期排序订单（硬约束2）
        List<Order> sortedOrders = new ArrayList<>(orders);
        sortedOrders.sort((o1, o2) -> {
            int dateComparison = o1.getDueDate().compareTo(o2.getDueDate());
            // 如果交付日期相同，根据变异索引引入不同的排序策略
            if (dateComparison == 0) {
                // 使用订单ID的哈希值和变异索引来确保确定性的随机排序
                int hash1 = o1.getId().hashCode();
                int hash2 = o2.getId().hashCode();
                return Integer.compare((hash1 + variationIndex) % 1000, (hash2 + variationIndex) % 1000);
            }
            return dateComparison;
        });

        // 步骤3：构建工序序列，保证订单内工序顺序（硬约束1）
        List<Operation> result = new ArrayList<>();
        for (Order order : sortedOrders) {
            // 获取该订单的所有工序并按sequence排序
            List<Operation> orderOperations = order.getOperations().stream()
                    .sorted(Comparator.comparingInt(Operation::getSequence))
                    .collect(Collectors.toList());
            result.addAll(orderOperations);
        }

        log.debug("EDD启发式(变异{})：订单优先级 {}", variationIndex,
                sortedOrders.stream().map(Order::getId).collect(Collectors.joining(" > ")));

        return result;
    }

    /**
     * 创建基于最短处理时间(SPT)的工序序列
     *
     * 硬约束保证：
     * 1. 工序执行顺序：同一订单的工序必须按sequence顺序执行
     * 2. 交付日期优先级：交付日期越早的订单优先级越高
     *
     * 启发式规则：在满足硬约束的前提下，交付日期相同的订单按总处理时间升序排列
     *
     * @param allOperations 所有工序
     * @param variationIndex 变异索引，用于产生不同的随机扰动
     * @return SPT排序的工序序列
     */
    private List<Operation> createSPTSequence(List<Operation> allOperations, int variationIndex) {
        // 步骤1：计算每个订单的总处理时间
        Map<String, Integer> orderTotalTime = new HashMap<>();
        for (Order order : orders) {
            int totalTime = order.getOperations().stream()
                    .mapToInt(Operation::getTotalProcessingTime)
                    .sum();
            orderTotalTime.put(order.getId(), totalTime);
        }

        // 步骤2：排序订单（硬约束2优先，然后SPT启发式）
        List<Order> sortedOrders = new ArrayList<>(orders);
        sortedOrders.sort((o1, o2) -> {
            // 首先按交付日期排序（硬约束2）
            int dateComparison = o1.getDueDate().compareTo(o2.getDueDate());
            if (dateComparison != 0) {
                return dateComparison;
            }

            // 交付日期相同时，按总处理时间排序（SPT启发式）
            int time1 = orderTotalTime.get(o1.getId());
            int time2 = orderTotalTime.get(o2.getId());
            int timeComparison = Integer.compare(time1, time2);

            // 如果处理时间也相同，根据变异索引引入不同的排序策略
            if (timeComparison == 0) {
                int hash1 = o1.getId().hashCode();
                int hash2 = o2.getId().hashCode();
                return Integer.compare((hash1 + variationIndex * 17) % 1000, (hash2 + variationIndex * 17) % 1000);
            }
            return timeComparison;
        });

        // 步骤3：构建工序序列，保证订单内工序顺序（硬约束1）
        List<Operation> result = new ArrayList<>();
        for (Order order : sortedOrders) {
            List<Operation> orderOperations = order.getOperations().stream()
                    .sorted(Comparator.comparingInt(Operation::getSequence))
                    .collect(Collectors.toList());
            result.addAll(orderOperations);
        }

        log.debug("SPT启发式(变异{})：订单优先级 {} (处理时间: {})", variationIndex,
                sortedOrders.stream().map(Order::getId).collect(Collectors.joining(" > ")),
                sortedOrders.stream().map(o -> orderTotalTime.get(o.getId()).toString()).collect(Collectors.joining(", ")));

        return result;
    }

    /**
     * 创建基于最长处理时间(LPT)的工序序列
     *
     * 硬约束保证：
     * 1. 工序执行顺序：同一订单的工序必须按sequence顺序执行
     * 2. 交付日期优先级：交付日期越早的订单优先级越高
     *
     * 启发式规则：在满足硬约束的前提下，交付日期相同的订单按总处理时间降序排列
     * LPT适用于负载均衡场景，优先处理耗时长的任务
     *
     * @param allOperations 所有工序
     * @param variationIndex 变异索引，用于产生不同的随机扰动
     * @return LPT排序的工序序列
     */
    private List<Operation> createLPTSequence(List<Operation> allOperations, int variationIndex) {
        // 步骤1：计算每个订单的总处理时间
        Map<String, Integer> orderTotalTime = new HashMap<>();
        for (Order order : orders) {
            int totalTime = order.getOperations().stream()
                    .mapToInt(Operation::getTotalProcessingTime)
                    .sum();
            orderTotalTime.put(order.getId(), totalTime);
        }

        // 步骤2：排序订单（硬约束2优先，然后LPT启发式）
        List<Order> sortedOrders = new ArrayList<>(orders);
        sortedOrders.sort((o1, o2) -> {
            // 首先按交付日期排序（硬约束2）
            int dateComparison = o1.getDueDate().compareTo(o2.getDueDate());
            if (dateComparison != 0) {
                return dateComparison;
            }

            // 交付日期相同时，按总处理时间降序排序（LPT启发式）
            int time1 = orderTotalTime.get(o1.getId());
            int time2 = orderTotalTime.get(o2.getId());
            int timeComparison = Integer.compare(time2, time1); // 注意：time2 vs time1 实现降序

            // 如果处理时间也相同，根据变异索引引入不同的排序策略
            if (timeComparison == 0) {
                int hash1 = o1.getId().hashCode();
                int hash2 = o2.getId().hashCode();
                return Integer.compare((hash1 + variationIndex * 23) % 1000, (hash2 + variationIndex * 23) % 1000);
            }
            return timeComparison;
        });

        // 步骤3：构建工序序列，保证订单内工序顺序（硬约束1）
        List<Operation> result = new ArrayList<>();
        for (Order order : sortedOrders) {
            List<Operation> orderOperations = order.getOperations().stream()
                    .sorted(Comparator.comparingInt(Operation::getSequence))
                    .collect(Collectors.toList());
            result.addAll(orderOperations);
        }

        log.debug("LPT启发式(变异{})：订单优先级 {} (处理时间: {})", variationIndex,
                sortedOrders.stream().map(Order::getId).collect(Collectors.joining(" > ")),
                sortedOrders.stream().map(o -> orderTotalTime.get(o.getId()).toString()).collect(Collectors.joining(", ")));

        return result;
    }

    /**
     * 支持多样性保护的父代选择
     *
     * @param population 当前种群
     * @return 选中的父代
     */
    private List<Chromosome> selectParentsWithDiversity(List<Chromosome> population) {
        List<Chromosome> parents = new ArrayList<>();

        for (int i = 0; i < populationSize; i++) {
            int selectedIndex = GAUtils.tournamentSelectionWithDiversity(
                    population, tournamentSize, diversityWeight);
            parents.add(population.get(selectedIndex).copy());
        }

        return parents;
    }

    /**
     * 精英保留的种群替换策略
     *
     * @param oldPopulation 旧种群
     * @param offspring 子代
     * @return 新种群
     */
    private List<Chromosome> replacePopulationWithElitism(List<Chromosome> oldPopulation,
                                                         List<Chromosome> offspring) {
        // 计算精英数量
        int eliteSize = Math.max(1, (int) (populationSize * eliteRatio));

        // 对旧种群按适应度排序
        oldPopulation.sort((c1, c2) -> Double.compare(c2.getFitness(), c1.getFitness()));
        List<Chromosome> elites = new ArrayList<>(oldPopulation.subList(0, eliteSize));

        // 对子代按适应度排序
        calculateFitness(offspring);
        offspring.sort((c1, c2) -> Double.compare(c2.getFitness(), c1.getFitness()));

        // 组成新种群
        List<Chromosome> newPopulation = new ArrayList<>(elites);
        int remaining = populationSize - eliteSize;

        for (int i = 0; i < remaining && i < offspring.size(); i++) {
            newPopulation.add(offspring.get(i));
        }

        // 如果子代不够，用旧种群补充
        while (newPopulation.size() < populationSize && newPopulation.size() < oldPopulation.size()) {
            newPopulation.add(oldPopulation.get(newPopulation.size()));
        }

        return newPopulation;
    }

    /**
     * 初始化种群（旧版本，保留作为备用）
     *
     * 创建初始种群的策略：
     * 1. 收集所有工序
     * 2. 生成多个随机排列作为初始染色体
     * 3. 保持每个订单内部工序的正确顺序
     *
     * @return 初始种群
     */
    @SuppressWarnings("unused")
    private List<Chromosome> initializePopulation() {
        log.info("开始初始化种群========================================");
        log.info("目的：以工序为单位，合并所有订单的工序创建初始种群");

        List<Chromosome> population = new ArrayList<>();
        List<Operation> allOperations = new ArrayList<>();

        // 收集所有工序
        for (Order order : orders) {
            allOperations.addAll(order.getOperations());
        }

        // 计算理论上的全排列数量
        long totalPermutations = GAUtils.calFactorial(allOperations.size());
        log.info("染色体基因数量：{}", allOperations.size());
        log.info("基因序列全排列存在{}种情况", totalPermutations);
        log.info("当前种群大小（父代染色体个数）：{}", populationSize);

        // 生成初始种群
        for (int i = 0; i < populationSize; i++) {
            // 随机打乱工序顺序，但保持每个订单的工序顺序
            List<Operation> shuffled = new ArrayList<>(allOperations);
            shufflePreservingOrder(shuffled);
            population.add(new Chromosome(shuffled));
        }

        log.info("初始化种群完成，生成{}个染色体", population.size());
        return population;
    }

    /**
     * 打乱工序顺序但保持每个订单内工序的正确顺序
     *
     * 策略：
     * 1. 按订单分组工序
     * 2. 随机打乱订单之间的顺序
     * 3. 保持每个订单内部工序的原有顺序
     *
     * @param operations 要打乱的工序列表
     */
    private void shufflePreservingOrder(List<Operation> operations) {
        // 按订单分组
        Map<String, List<Operation>> orderGroups = operations.stream()
                .collect(Collectors.groupingBy(op -> op.getOrder().getId()));

        // 创建订单ID列表并打乱
        List<String> orderIds = new ArrayList<>(orderGroups.keySet());
        Collections.shuffle(orderIds);

        // 重建工序列表，保持订单内工序顺序，打乱订单间顺序
        operations.clear();
        for (String orderId : orderIds) {
            List<Operation> orderOperations = orderGroups.get(orderId);
            // 按工序顺序排序，确保订单内工序顺序正确
            orderOperations.sort(Comparator.comparingInt(Operation::getSequence));
            operations.addAll(orderOperations);
        }
    }

    /**
     * 计算种群中所有染色体的适应度
     *
     * @param population 种群
     */
    private void calculateFitness(List<Chromosome> population) {
        log.info("开始计算种群适应度...");
        int chromosomeCount = 0;

        for (Chromosome chromosome : population) {
            chromosome.setFitness(calculateFitness(chromosome));
            chromosomeCount++;

            if (chromosomeCount % 10 == 0) {
                log.info("已计算{}个染色体的适应度", chromosomeCount);
            }
        }

        log.info("种群适应度计算完成");
    }

    /**
     * 计算单个染色体的适应度
     *
     * 适应度计算考虑因素：
     * 1. 是否超出交付期限（硬约束）
     * 2. 是否存在机器冲突（硬约束）
     * 3. 设备利用率（软目标）
     * 4. 延迟时间（软目标）
     *
     * @param chromosome 染色体
     * @return 适应度值（0.0-1.0，越高越好）
     */
    private double calculateFitness(Chromosome chromosome) {
        // 重置设备状态
        resetMachineAvailability();
        chromosome.setHasMachineConflicts(false);

        // 跟踪每个订单最后一道工序的完成时间
        Map<String, LocalDateTime> lastOperationEndTime = new HashMap<>();

        // 为每个工序进行排产
        for (Operation op : chromosome.getGeneSequence()) {
            scheduleOperation(op, lastOperationEndTime, chromosome);

            // 硬约束检查：超出交付日期
            if (op.getEndTime() != null && op.getEndTime().isAfter(op.getOrder().getDueDate())) {
                return 0.0; // 不可行方案
            }

            // 硬约束检查：平均排产模式不允许加班
            if (schedulingMode == SchedulingMode.AVERAGE && isOperationUsingOvertime(op)) {
                return 0.0; // 不可行方案
            }
        }

        // 硬约束检查：机器冲突
        if (chromosome.hasMachineConflicts()) {
            return 0.1; // 冲突方案适应度极低但不为0，保留进化可能性
        }

        // 计算软目标适应度
        return calculateSoftObjectiveFitness();
    }

    /**
     * 为单个工序进行排产
     *
     * @param op 要排产的工序
     * @param lastOperationEndTime 订单最后工序完成时间映射
     * @param chromosome 所属染色体
     */
    private void scheduleOperation(Operation op, Map<String, LocalDateTime> lastOperationEndTime, Chromosome chromosome) {
//        op.setHasMachineConflict(false);
//        op.clearProductIntervals();
//
//        // 确定工序开始时间：取设备可用时间和同一订单上一工序完成时间的最大值
//        LocalDateTime orderLastEndTime = lastOperationEndTime.getOrDefault(op.getOrder().getId(), globalStartTime);
//        LocalDateTime earliestPossibleStart = op.getMachine().getNextAvailableTime().isAfter(orderLastEndTime) ?
//                op.getMachine().getNextAvailableTime() : orderLastEndTime;
//
//        // 根据排产方式调整开始时间
//        LocalDateTime startTime = adjustStartTimeByMode(op, earliestPossibleStart);
//
//        // 计算每个产品的加工时间区间
//        scheduleProductIntervals(op, startTime);
//
//        // 检查机器冲突
//        if (op.getMachine().hasConflict(op.getStartTime(), op.getEndTime())) {
//            op.setHasMachineConflict(true);
//            chromosome.setHasMachineConflicts(true);
//        }
//
//        // 更新设备状态
//        op.getMachine().addInterval(op.getStartTime(), op.getEndTime());
//
//        // 更新订单最后工序完成时间
//        lastOperationEndTime.put(op.getOrder().getId(), op.getEndTime());
//
//        // 检查是否使用加班时间
//        op.setOvertime(isOperationUsingOvertime(op));
    }

    /**
     * 根据排产模式调整开始时间
     *
     * @param op 工序
     * @param earliestPossibleStart 最早可能开始时间
     * @return 调整后的开始时间
     */
    private LocalDateTime adjustStartTimeByMode(Operation op, LocalDateTime earliestPossibleStart) {
        LocalDateTime startTime;

        if (schedulingMode == SchedulingMode.BACKWARD) {
            // 倒排：从交付日期倒推
            startTime = calculateBackwardStartTime(op, earliestPossibleStart);
        } else {
            startTime = earliestPossibleStart;
        }

        // 确保不早于全局开始时间
        if (startTime.isBefore(globalStartTime)) {
            startTime = globalStartTime;
        }

        // AVERAGE模式特殊处理：18:00开始的工序延迟到次日8:00
        if (schedulingMode == SchedulingMode.AVERAGE && startTime.getHour() == WORK_END_HOUR) {
            startTime = startTime.plusDays(1).withHour(WORK_START_HOUR).withMinute(0);
        }

        return startTime;
    }

    /**
     * 为工序安排产品时间区间
     *
     * @param op 工序
     * @param startTime 开始时间
     */
    private void scheduleProductIntervals(Operation op, LocalDateTime startTime) {
        LocalDateTime currentTime = startTime;

        // 为每个产品安排时间区间
        for (int i = 0; i < op.getOrder().getQuantity(); i++) {
            LocalDateTime productEndTime = calculateEndTime(currentTime, op.getUnitProcessingTime());
            op.addProductInterval(new ProductInterval(i + 1, currentTime, productEndTime));
            currentTime = productEndTime;
        }

        // 设置工序的整体时间范围
        if (!op.getProductIntervals().isEmpty()) {
            op.setStartTime(op.getProductIntervals().get(0).getStart());
            op.setEndTime(op.getProductIntervals().get(op.getProductIntervals().size() - 1).getEnd());
        }
    }

    /**
     * 检查工序是否使用了加班时间
     *
     * @param op 工序
     * @return 是否使用加班时间
     */
    private boolean isOperationUsingOvertime(Operation op) {
        return op.getProductIntervals().stream()
                .anyMatch(interval -> isOvertime(interval.getStart()) || isOvertime(interval.getEnd()));
    }

    /**
     * 计算软目标的适应度
     *
     * 软目标包括：
     * 1. 最小化延迟时间
     * 2. 最大化设备利用率
     *
     * @return 软目标适应度值
     */
    private double calculateSoftObjectiveFitness() {
        double totalDelay = 0;
        double totalAvailableTime = 0;

        // 计算延迟和可用时间
        for (Order order : orders) {
            Operation lastOp = order.getLastOperation();
            if (lastOp != null && lastOp.getEndTime() != null) {
                LocalDateTime completionTime = lastOp.getEndTime();

                // 计算延迟时间
                if (completionTime.isAfter(order.getDueDate())) {
                    totalDelay += Duration.between(order.getDueDate(), completionTime).toMinutes();
                }
            }

            // 计算订单可用总时间
            long days = ChronoUnit.DAYS.between(globalStartTime, order.getDueDate()) + 1;
            int dailyAvailable = calculateDailyAvailableMinutes();
            totalAvailableTime += days * dailyAvailable;
        }

        // 计算设备利用率
        double machineUtilization = calculateMachineUtilization();

        // 适应度计算：延迟因子 * 0.7 + 设备利用率 * 0.3
        double delayFactor = totalAvailableTime > 0 ? 1 - (totalDelay / totalAvailableTime) : 1;
        return Math.max(0, delayFactor * 0.7 + machineUtilization * 0.3);
    }

    /**
     * 计算每日可用工作时间（分钟）
     *
     * @return 每日可用分钟数
     */
    private int calculateDailyAvailableMinutes() {
        int normalWorkMinutes = (MORNING_END_HOUR - WORK_START_HOUR) * 60 +
                               (WORK_END_HOUR - AFTERNOON_START_HOUR) * 60;

        if (schedulingMode == SchedulingMode.AVERAGE) {
            return normalWorkMinutes;
        } else {
            // 允许加班
            return normalWorkMinutes + (OVERTIME_END_HOUR - OVERTIME_START_HOUR) * 60;
        }
    }

    /**
     * 计算设备利用率
     *
     * @return 设备利用率（0.0-1.0）
     */
    private double calculateMachineUtilization() {
        double totalWorkingTime = 0;
        double totalAvailableTime = 0;

        for (Machine machine : machines) {
            // 计算设备总工作时间
            long workTime = 0;
            for (Order order : orders) {
//                for (Operation op : order.getOperations()) {
//                    if (op.getMachine().getId().equals(machine.getId())) {
//                        workTime += op.getTotalProcessingTime();
//                    }
//                }
            }

            // 计算设备总可用时间
            LocalDateTime latestDue = orders.stream()
                    .map(Order::getDueDate)
                    .max(LocalDateTime::compareTo)
                    .orElse(globalStartTime);

            long days = ChronoUnit.DAYS.between(globalStartTime, latestDue) + 1;
            int dailyAvailable = calculateDailyAvailableMinutes();
            totalAvailableTime += days * dailyAvailable;
            totalWorkingTime += workTime;
        }

        return totalAvailableTime > 0 ? totalWorkingTime / totalAvailableTime : 0;
    }

    // ============ 时间计算相关方法 ============

    /**
     * 计算倒排的开始时间
     */
    private LocalDateTime calculateBackwardStartTime(Operation op, LocalDateTime earliestPossibleStart) {
        // 找到同一订单的下一道工序
        Operation nextOp = op.getOrder().getOperationBySequence(op.getSequence() + 1);

        // 确定最晚完成时间
        LocalDateTime latestPossibleEnd;
        if (nextOp == null) {
            // 最后一道工序，最晚完成时间是订单交付日期
            latestPossibleEnd = op.getOrder().getDueDate();
        } else {
            latestPossibleEnd = nextOp.getStartTime() != null ? nextOp.getStartTime() : op.getOrder().getDueDate();
        }

        // 计算最晚开始时间
        LocalDateTime latestStart = subtractWorkingTime(latestPossibleEnd, op.getTotalProcessingTime());

        // 开始时间不能早于最早可能开始时间
        LocalDateTime actualEarliestStart = earliestPossibleStart.isBefore(globalStartTime) ?
                globalStartTime : earliestPossibleStart;

        return actualEarliestStart.isAfter(latestStart) ? actualEarliestStart : latestStart;
    }

    /**
     * 从结束时间减去工作时间，得到开始时间（考虑非工作时间）
     */
    private LocalDateTime subtractWorkingTime(LocalDateTime endTime, int minutes) {
        if (minutes <= 0) {
            return endTime;
        }

        LocalDateTime currentTime = endTime;
        int remaining = minutes;

        while (remaining > 0) {
            if (isRestTime(currentTime) || isNonWorkingTime(currentTime, true)) {
                currentTime = getPreviousWorkingPeriodEnd(currentTime);
                continue;
            }

            int timeInCurrentPeriod = getRemainingTimeInPreviousPeriod(currentTime);
            int processInThisPeriod = Math.min(remaining, timeInCurrentPeriod);

            currentTime = currentTime.minusMinutes(processInThisPeriod);
            remaining -= processInThisPeriod;
        }

        return currentTime.isBefore(globalStartTime) ? globalStartTime : currentTime;
    }

    /**
     * 计算结束时间，考虑工作时间和休息时间
     */
    private LocalDateTime calculateEndTime(LocalDateTime startTime, int processingTime) {
        if (processingTime <= 0) {
            return startTime;
        }

        LocalDateTime currentTime = startTime;
        int remainingTime = processingTime;

        while (remainingTime > 0) {
            // 跳过休息时间
            if (isRestTime(currentTime)) {
                currentTime = currentTime.withHour(AFTERNOON_START_HOUR).withMinute(0);
                continue;
            }

            // 跳过非工作时间
            if (isNonWorkingTime(currentTime, false)) {
                currentTime = getNextWorkingPeriodStart(currentTime);
                continue;
            }

            // 计算当前时段可处理的时间
            int timeInCurrentPeriod = getRemainingTimeInPeriod(currentTime);
            int processInThisPeriod = Math.min(remainingTime, timeInCurrentPeriod);

            currentTime = currentTime.plusMinutes(processInThisPeriod);
            remainingTime -= processInThisPeriod;
        }

        return currentTime;
    }

    // ============ 时间判断辅助方法 ============

    /**
     * 检查是否是午休时间（12:00-13:00）
     */
    private boolean isRestTime(LocalDateTime time) {
        int hour = time.getHour();
        return hour == MORNING_END_HOUR || (hour == AFTERNOON_START_HOUR && time.getMinute() == 0);
    }

    /**
     * 检查是否是非工作时间
     */
    private boolean isNonWorkingTime(LocalDateTime time, boolean isBackward) {
        int hour = time.getHour();

        if (schedulingMode == SchedulingMode.AVERAGE) {
            return hour < WORK_START_HOUR || hour >= WORK_END_HOUR || isRestTime(time);
        }

        return hour < WORK_START_HOUR || hour >= OVERTIME_END_HOUR || isRestTime(time);
    }

    /**
     * 检查是否是加班时间（18:00-20:00）
     */
    private boolean isOvertime(LocalDateTime time) {
        int hour = time.getHour();
        return hour >= OVERTIME_START_HOUR && hour < OVERTIME_END_HOUR;
    }

    /**
     * 获取下一个工作时段的开始时间
     */
    private LocalDateTime getNextWorkingPeriodStart(LocalDateTime time) {
        int hour = time.getHour();

        if (hour < WORK_START_HOUR) {
            return time.withHour(WORK_START_HOUR).withMinute(0);
        } else if (hour >= MORNING_END_HOUR && hour < AFTERNOON_START_HOUR) {
            return time.withHour(AFTERNOON_START_HOUR).withMinute(0);
        } else {
            return time.plusDays(1).withHour(WORK_START_HOUR).withMinute(0);
        }
    }

    /**
     * 获取当前时段剩余的工作时间
     */
    private int getRemainingTimeInPeriod(LocalDateTime time) {
        int hour = time.getHour();
        int minute = time.getMinute();
        boolean allowOvertime = schedulingMode != SchedulingMode.AVERAGE;

        if (hour < WORK_START_HOUR) {
            return 0;
        } else if (hour < MORNING_END_HOUR) {
            return (MORNING_END_HOUR - hour) * 60 - minute;
        } else if (hour == MORNING_END_HOUR) {
            return 0;
        } else if (hour < WORK_END_HOUR) {
            return (WORK_END_HOUR - hour) * 60 - minute;
        } else if (hour < OVERTIME_END_HOUR && allowOvertime) {
            return (OVERTIME_END_HOUR - hour) * 60 - minute;
        } else {
            return 0;
        }
    }

    /**
     * 获取前一个工作时段的结束时间
     */
    private LocalDateTime getPreviousWorkingPeriodEnd(LocalDateTime time) {
        int hour = time.getHour();
        boolean allowOvertime = schedulingMode != SchedulingMode.AVERAGE;

        if (hour >= OVERTIME_END_HOUR || hour < WORK_START_HOUR) {
            if (allowOvertime) {
                return time.minusDays(1).withHour(OVERTIME_END_HOUR).withMinute(0);
            } else {
                return time.minusDays(1).withHour(WORK_END_HOUR).withMinute(0);
            }
        } else if (hour == MORNING_END_HOUR || (hour == AFTERNOON_START_HOUR && time.getMinute() == 0)) {
            return time.withHour(MORNING_END_HOUR).withMinute(0);
        } else if (hour < MORNING_END_HOUR) {
            if (allowOvertime) {
                return time.minusDays(1).withHour(OVERTIME_END_HOUR).withMinute(0);
            } else {
                return time.minusDays(1).withHour(WORK_END_HOUR).withMinute(0);
            }
        } else if (hour < OVERTIME_START_HOUR) {
            return time.withHour(MORNING_END_HOUR).withMinute(0);
        } else {
            return time.withHour(WORK_END_HOUR).withMinute(0);
        }
    }

    /**
     * 获取当前时段可以往前推的工作时间
     */
    private int getRemainingTimeInPreviousPeriod(LocalDateTime time) {
        int hour = time.getHour();
        int minute = time.getMinute();
        boolean allowOvertime = schedulingMode != SchedulingMode.AVERAGE;

        if (hour >= OVERTIME_START_HOUR && hour < OVERTIME_END_HOUR && allowOvertime) {
            return (hour - OVERTIME_START_HOUR) * 60 + minute;
        } else if (hour >= AFTERNOON_START_HOUR && hour < OVERTIME_START_HOUR) {
            return (hour - AFTERNOON_START_HOUR) * 60 + minute;
        } else if (hour >= WORK_START_HOUR && hour < MORNING_END_HOUR) {
            return (hour - WORK_START_HOUR) * 60 + minute;
        }
        return 0;
    }

    /**
     * 重置设备可用时间为全局统一开始时间
     */
    private void resetMachineAvailability() {
        for (Machine machine : machines) {
            machine.resetToTime(globalStartTime);
        }
    }

    // ============ 遗传算法操作方法 ============

    /**
     * 选择父代（锦标赛选择法）- 旧版本，保留作为备用
     */
    @SuppressWarnings("unused")
    private List<Chromosome> selectParents(List<Chromosome> population) {
        List<Chromosome> parents = new ArrayList<>();

        for (int i = 0; i < populationSize; i++) {
            Chromosome best = null;
            for (int j = 0; j < tournamentSize; j++) {
                int randomIdx = GAUtils.randomInt(0, population.size());
                Chromosome candidate = population.get(randomIdx);
                if (best == null || candidate.getFitness() > best.getFitness()) {
                    best = candidate;
                }
            }
            parents.add(best.copy());
        }

        return parents;
    }

    /**
     * 交叉操作（两点交叉）
     */
    private List<Chromosome> crossover(List<Chromosome> parents) {
        List<Chromosome> offspring = new ArrayList<>();

        for (int i = 0; i < populationSize; i += 2) {
            Chromosome parent1 = parents.get(i);
            Chromosome parent2 = parents.get(Math.min(i + 1, populationSize - 1));

            if (GAUtils.shouldExecute(crossoverRate)) {
                performCrossover(parent1, parent2, offspring);
            } else {
                offspring.add(parent1.copy());
                offspring.add(parent2.copy());
            }
        }

        return offspring.subList(0, Math.min(populationSize, offspring.size()));
    }

    /**
     * 执行两点交叉操作
     */
    private void performCrossover(Chromosome parent1, Chromosome parent2, List<Chromosome> offspring) {
        int size = parent1.getGeneLength();
        if (size < 2) {
            offspring.add(parent1.copy());
            offspring.add(parent2.copy());
            return;
        }

        int point1 = GAUtils.randomInt(0, size);
        int point2 = GAUtils.randomInt(0, size);

        if (point1 > point2) {
            int temp = point1;
            point1 = point2;
            point2 = temp;
        }

        // 创建子代
        Chromosome child1 = parent1.copy();
        Chromosome child2 = parent2.copy();

        // 交换交叉点之间的基因
        List<Operation> temp = new ArrayList<>(child1.getGeneSequence().subList(point1, point2 + 1));
        child1.getGeneSequence().subList(point1, point2 + 1).clear();
        child1.getGeneSequence().addAll(point1, child2.getGeneSequence().subList(point1, point2 + 1));
        child2.getGeneSequence().subList(point1, point2 + 1).clear();
        child2.getGeneSequence().addAll(point1, temp);

        // 修复染色体
        repairChromosome(child1);
        repairChromosome(child2);

        offspring.add(child1);
        offspring.add(child2);
    }

    /**
     * 变异操作（交换变异）
     */
    private void mutate(List<Chromosome> population) {
        for (Chromosome chromosome : population) {
            if (GAUtils.shouldExecute(mutationRate) && chromosome.getGeneLength() > 1) {
                performMutation(chromosome);
            }
        }
    }

    /**
     * 执行变异操作
     */
    private void performMutation(Chromosome chromosome) {
        int size = chromosome.getGeneLength();
        int pos1 = GAUtils.randomInt(0, size);
        int pos2 = GAUtils.randomInt(0, size);

        while (pos1 == pos2 && size > 1) {
            pos2 = GAUtils.randomInt(0, size);
        }

        Operation op1 = chromosome.getGeneSequence().get(pos1);
        Operation op2 = chromosome.getGeneSequence().get(pos2);

        // 检查是否可以交换（不能破坏订单工序顺序）
        if (!op1.getOrder().getId().equals(op2.getOrder().getId())) {
            chromosome.swapOperations(pos1, pos2);
        }
    }

    /**
     * 修复染色体，确保工序顺序正确
     */
    private void repairChromosome(Chromosome chromosome) {
        Map<String, List<Operation>> orderOperations = new LinkedHashMap<>();

        // 按订单分组工序
        for (Operation op : chromosome.getGeneSequence()) {
            orderOperations.computeIfAbsent(op.getOrder().getId(), k -> new ArrayList<>()).add(op);
        }

        // 清除原有序列
        chromosome.getGeneSequence().clear();

        // 按正确顺序重建
        for (List<Operation> ops : orderOperations.values()) {
            ops.sort(Comparator.comparingInt(Operation::getSequence));
            chromosome.getGeneSequence().addAll(ops);
        }

        // 解决机器冲突
        resolveMachineConflicts(chromosome);
    }

    /**
     * 尝试解决机器冲突
     */
    private void resolveMachineConflicts(Chromosome chromosome) {
        Map<String, List<Operation>> machineOps = new HashMap<>();
        for (Operation op : chromosome.getGeneSequence()) {
//            machineOps.computeIfAbsent(op.getMachine().getId(), k -> new ArrayList<>()).add(op);
        }

        // 对每个机器的工序进行排序
        for (List<Operation> ops : machineOps.values()) {
            ops.sort((o1, o2) -> {
                if (o1.getOrder().getId().equals(o2.getOrder().getId())) {
                    return Integer.compare(o1.getSequence(), o2.getSequence());
                }
                return Integer.compare(
                        chromosome.getGeneSequence().indexOf(o1),
                        chromosome.getGeneSequence().indexOf(o2)
                );
            });
        }

        // 重新构建基因序列
        rebuildGeneSequence(chromosome, machineOps);
    }

    /**
     * 重新构建基因序列
     */
    private void rebuildGeneSequence(Chromosome chromosome, Map<String, List<Operation>> machineOps) {
        List<Operation> newSequence = new ArrayList<>();
        Set<Operation> added = new HashSet<>();

        for (Operation op : chromosome.getGeneSequence()) {
            if (!added.contains(op)) {
//                List<Operation> machineOpsList = machineOps.get(op.getMachine().getId());
//                for (Operation machineOp : machineOpsList) {
//                    if (!added.contains(machineOp)) {
//                        newSequence.add(machineOp);
//                        added.add(machineOp);
//                    }
//                }
            }
        }

        chromosome.setGeneSequence(newSequence);
    }

    /**
     * 替换种群（精英保留策略）- 旧版本，保留作为备用
     */
    @SuppressWarnings("unused")
    private List<Chromosome> replacePopulation(List<Chromosome> oldPopulation, List<Chromosome> offspring) {
        // 保留适应度最高的20%
        int eliteSize = Math.max(1, (int) (populationSize * 0.2));
        oldPopulation.sort((c1, c2) -> Double.compare(c2.getFitness(), c1.getFitness()));
        List<Chromosome> elites = new ArrayList<>(oldPopulation.subList(0, eliteSize));

        // 从后代中选择剩余个体
        offspring.sort((c1, c2) -> Double.compare(c2.getFitness(), c1.getFitness()));
        List<Chromosome> newPopulation = new ArrayList<>(elites);

        int remaining = populationSize - eliteSize;
        for (int i = 0; i < remaining && i < offspring.size(); i++) {
            newPopulation.add(offspring.get(i));
        }

        return newPopulation;
    }

    // ============ 结果输出方法 ============

    /**
     * 打印排产结果
     */
    public void printSchedule(Chromosome best) {
        if (best == null) {
            System.out.println("没有找到可行的排产方案");
            return;
        }

        System.out.println("=".repeat(80));
        System.out.println("最优排产方案（适应度: " + String.format("%.4f", best.getFitness()) + "）");
        System.out.println("所有订单统一开始时间: " + globalStartTime.format(formatter));
        System.out.println("排产方式: " + schedulingMode);
        System.out.println("是否存在机器冲突: " + (best.hasMachineConflicts() ? "是" : "否"));
        System.out.println("=".repeat(80));

        printOrderBasicInfo();
        printOperationDetails();
        printMachineSchedule(best);
        printOrderCompletionStatus();

        System.out.println("=".repeat(80));
    }

    /**
     * 打印订单基本信息
     */
    private void printOrderBasicInfo() {
        System.out.println("\n订单基本信息:");
        System.out.println("-".repeat(80));
        for (Order order : orders) {
            System.out.printf("订单 %s: 数量 %d个, 开始日期 %s, 交付日期 %s%n",
                    order.getId(), order.getQuantity(),
                    order.getStartDate().format(formatter),
                    order.getDueDate().format(formatter));
        }
    }

    /**
     * 打印工序详细信息
     */
    private void printOperationDetails() {
        System.out.println("\n各产品工序时间明细:");
        System.out.println("-".repeat(80));

        List<Order> sortedOrders = new ArrayList<>(orders);
        sortedOrders.sort(Comparator.comparing(Order::getId));

        for (Order order : sortedOrders) {
            System.out.println("产品（订单）" + order.getId() + " 的工序:");

            List<Operation> sortedOps = new ArrayList<>(order.getOperations());
            sortedOps.sort(Comparator.comparingInt(Operation::getSequence));

            for (Operation op : sortedOps) {
                printOperationDetail(op);
            }
            System.out.println();
        }
    }

    /**
     * 打印单个工序详细信息
     */
    private void printOperationDetail(Operation op) {
        System.out.println("\n工序ID: " + op.getId() +
                ", 工序顺序: " + op.getSequence() +
//                ", 设备: " + op.getMachine().getId() +
                ", 单位时间: " + op.getUnitProcessingTime() + "分钟" +
                ", 总数量: " + op.getOrder().getQuantity() + "个");
        System.out.println("产品序号\t开始时间\t\t结束时间\t\t是否加班");

        for (ProductInterval interval : op.getProductIntervals()) {
            boolean isOvertimeInterval = isOvertime(interval.getStart()) || isOvertime(interval.getEnd());
            System.out.printf("%d\t\t%s\t%s\t%s%n",
                    interval.getProductIndex(),
                    interval.getStart().format(formatter),
                    interval.getEnd().format(formatter),
                    isOvertimeInterval ? "是" : "否");
        }
    }

    /**
     * 打印设备排产信息
     */
    private void printMachineSchedule(Chromosome best) {
        System.out.println("\n设备排产信息:");
        System.out.println("-".repeat(80));

        Map<String, List<Operation>> machineOps = new TreeMap<>();
        for (Operation op : best.getGeneSequence()) {
//            machineOps.computeIfAbsent(op.getMachine().getId(), k -> new ArrayList<>()).add(op);
        }

        for (Map.Entry<String, List<Operation>> entry : machineOps.entrySet()) {
            System.out.println("设备 " + entry.getKey() + " 排产:");

            for (Operation op : entry.getValue()) {
                printMachineOperationDetail(op);
            }
            System.out.println();
        }
    }

    /**
     * 打印设备工序详细信息
     */
    private void printMachineOperationDetail(Operation op) {
        System.out.println("\n工序: " + op.getId() +
                ", 订单: " + op.getOrder().getId() +
                ", 单位时间: " + op.getUnitProcessingTime() + "分钟" +
                ", 总数量: " + op.getOrder().getQuantity() + "个");
        System.out.println("产品序号\t开始时间\t\t结束时间\t\t是否加班\t是否冲突");

        for (ProductInterval interval : op.getProductIntervals()) {
            boolean isOvertimeInterval = isOvertime(interval.getStart()) || isOvertime(interval.getEnd());
            System.out.printf("%d\t\t%s\t%s\t%s\t\t%s%n",
                    interval.getProductIndex(),
                    interval.getStart().format(formatter),
                    interval.getEnd().format(formatter),
                    isOvertimeInterval ? "是" : "否",
                    op.hasMachineConflict() ? "是" : "否");
        }
    }

    /**
     * 打印订单完成情况
     */
    private void printOrderCompletionStatus() {
        System.out.println("\n订单完成情况:");
        System.out.println("-".repeat(80));
        for (Order order : orders) {
            Operation lastOp = order.getLastOperation();
            if (lastOp != null && !lastOp.getProductIntervals().isEmpty()) {
                ProductInterval lastInterval = lastOp.getProductIntervals().get(lastOp.getProductIntervals().size() - 1);
                LocalDateTime completionTime = lastInterval.getEnd();
                String status = !completionTime.isAfter(order.getDueDate()) ? "按时完成" : "延迟完成";

                System.out.printf("订单 %s: 开始日期 %s, 交付日期 %s, 完成日期 %s, %s%n",
                        order.getId(),
                        order.getStartDate().format(formatter),
                        order.getDueDate().format(formatter),
                        completionTime.format(formatter),
                        status);
            }
        }
    }
}
